package cn.yrec.rain.analysis.service.impl;

import cn.hutool.extra.cglib.CglibUtil;
import cn.yrec.rain.analysis.mappers.RaPDayRtMapper;
import cn.yrec.rain.analysis.mappers.RaPDayRtVoMapper;
import cn.yrec.rain.analysis.model.RaPDayRt;
import cn.yrec.rain.analysis.service.DataProcessService;
import cn.yrec.rain.analysis.utils.DateUtils;
import cn.yrec.rain.analysis.vo.RaPDayRtVo;
import cn.yrec.rain.analysis.vo.RainModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 描述:
 *  数据处理业务层实现类
 * @createDate: 2023/03/31 0:12
 * @author: yanglichen
 */
@Service
public class DataProcessServiceImpl implements DataProcessService {

    @Autowired
    private RaPDayRtMapper raPDayRtMapper;
    @Autowired
    private RaPDayRtVoMapper raPDayRtVoMapper;

    /**
     * 方法描述: 查询站码列表对应的站码在小于某一个日期,降雨量<=降雨阈值的全部信息
     * 初步封装到List<Map<>>中,将在业务层转化为Map<>对象
     *
     * @param rainModel 降雨参数
     * @return 日期和对应天数的计数项
     * @author yanglichen
     * @date 2023-03-31 00:13
     **/
    @Transactional
    @Override
    public Map<Date, Integer> getRainfallCountMap(RainModel rainModel) {
        // 站码列表
        List<String> stcdList = rainModel.getStcdList();
        // 降雨的阈值
        Double rainfallThreshold = rainModel.getRainfallParameters().getRainfallThreshold();
        Map<Date, Integer> dateCountMap = new HashMap<>();
        // 得到目前的日期(年月日格式)
        Date selectDate = DateUtils.getNotHourDate(new Date());
        //查询数据库得到结果级
        List<Map<String, Object>> mapList = raPDayRtMapper.getDatesCountRainfall(stcdList, selectDate, rainfallThreshold);
        for (Map<String, Object> map : mapList) {
            Date date = null;
            Integer count = null;
            /*
             每个List中的元素都是这样的一个Map
             {VALUE=32, KEY=2020-07-18 00:00:00.0}
             */
            for (Map.Entry<String, Object> m : map.entrySet()){
                if("KEY".equalsIgnoreCase(m.getKey())){
                    date = (Date) m.getValue();
                }
                if ("VALUE".equalsIgnoreCase(m.getKey())) {
                    count = Integer.valueOf(m.getValue().toString());
                }
                dateCountMap.put(date, count);
            }
        }
        return dateCountMap;
    }

    /**
     * 方法描述: 得到站码列表在起始日之前的所有的信息
     * 封装成Map(便于后续计算降雨特征值信息的检索)
     *
     * @param rainModel 降雨参数
     * @return 封装站码列表全部信息的Map
     * 例如:{
     *  站码1 = {日期1=雨量站全部信息实例1, 日期2=雨量站全部信息实例2...},
     *  站码2 = {日期1=雨量站全部信息实例1, 日期2=雨量站全部信息实例2...},
     *  ....
     * }
     * @author yanglichen
     * @date 2020-07-24 10:27
     **/
    @Transactional
    @Override
    public Map<String, Map<Date, RaPDayRtVo>> getAllInformationMap(RainModel rainModel) {
        Map<String, Map<Date, RaPDayRtVo>> allInformationMap = new HashMap<>();
        // 得到站码列表
        List<String> stcdList = rainModel.getStcdList();
        //得到 当日00:00 时刻的Date (防止传入不同的时间对象,导致无法使用MyBatis二级缓存的数据)
        Date now = DateUtils.getNotHourDate(new Date());
        // 关联查询的得到包含降雨量的面积和权重信息
        List<RaPDayRtVo> raPDayRtVoList = raPDayRtVoMapper.getAllInformation(stcdList, now);
        //得到按照站码分类的数据
        List<List<RaPDayRtVo>> raPDayRtVosList = getListRaPDayRtVoListByStringList(raPDayRtVoList, stcdList);
        //遍历站码列表进行构造外层Map
        for (String stcd : stcdList) {
            //初始化内层Map
            Map<Date, RaPDayRtVo> raPDayRtVoMap = null;
            // 构造迭代器
            Iterator<List<RaPDayRtVo>> iterator = raPDayRtVosList.iterator();
            while (iterator.hasNext()) {
                List<RaPDayRtVo> next = iterator.next();
                if(next.size()!=0){
                    //找到站码列表对应的列表
                    if (next.get(0).getStcd().equalsIgnoreCase(stcd)) {
                        raPDayRtVoMap = new HashMap<>();
                        //遍历该列表对象
                        for (RaPDayRtVo raPDayRtVo : next) {
                            //存放内层Map数据
                            raPDayRtVoMap.put(raPDayRtVo.getDate(), raPDayRtVo);
                        }
                        iterator.remove();
                    }
                }
            }
            allInformationMap.put(stcd, raPDayRtVoMap);
        }
        return allInformationMap;
    }

    /**
     * 方法描述: 根据开始时间，结束时间，站码列表，降雨阈值得到时间范围内的累计降雨量
     *
     * @param startDate         开始时间
     * @param endDate           结束时间
     * @param stcdList          站码列表
     * @param rainfallThreshold 降雨阈值
     * @return 有降雨的数据，其中rf 表示累计雨量
     * @author yanglichen
     * @date 2023-08-21 11:05
     **/
    @Override
    public List<RaPDayRt> getSumRainByStartDateEndDateStcdListAndRainThreshold(
            Date startDate, Date endDate, List<String> stcdList, Double rainfallThreshold) {
        return raPDayRtMapper.getSumRainByStartDateEndDateStcdListAndRainThreshold(
                startDate, endDate, stcdList, rainfallThreshold);
    }

    /**
     * 方法描述: 根据站码列表得到雨量站详细信息的集合列表
     *
     * @param raPDayRtResultList 查询出来的雨量站结果列表
     * @param stcdList           站码列表
     * @return [雨量站1的列表, 雨量站2的列表,雨量站3的列表....]
     * @author yanglichen
     * @date 2020-07-06 18:27
     **/
    private static List<List<RaPDayRtVo>> getListRaPDayRtVoListByStringList(
            List<RaPDayRtVo> raPDayRtResultList,
            List<String> stcdList) {
        List<List<RaPDayRtVo>> raPDayRtVoLists = new ArrayList<>();
        List<RaPDayRtVo> raPDayRtResultListCopy = CglibUtil.copyList(raPDayRtResultList, RaPDayRtVo::new);
        //遍历站码列表
        for (String stcd : stcdList) {
            List<RaPDayRtVo> raPDayRtVoList = new ArrayList<>();
            // 构造迭代器
            Iterator<RaPDayRtVo> iterator = raPDayRtResultListCopy.iterator();
            //遍历雨量站结果集
            while (iterator.hasNext()) {
                RaPDayRtVo raPDayRtVo = iterator.next();
                //如果站码相同就放入list中
                if (raPDayRtVo.getStcd().equalsIgnoreCase(stcd)) {
                    raPDayRtVoList.add(raPDayRtVo);
                    iterator.remove();
                }
            }
            raPDayRtVoLists.add(raPDayRtVoList);
        }
        return raPDayRtVoLists;
    }
}
